﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using addrSpaceHolder = System.Byte; // Aduc has 256 bytes on chip RAM

namespace WpfApplication4
{


    /// <summary>
    /// Interaction logic for Core_controlxaml.xaml
    /// </summary>
    public partial class Core_controlxaml : System.Windows.Controls.Image 
    {
        /*  BYTE Register  */
        const addrSpaceHolder P0 = 0x80;
        const addrSpaceHolder SP = 0x81;
        const addrSpaceHolder DPL = 0x82;
        const addrSpaceHolder DPH = 0x83;
        //const addrSpaceHolder DPP = 0x84;
        // 0x85-0x86 RESERVED
        /*
        * Assuming, that Instruction Pointer will be held in registers 0x85 (Low byte) and 0x86 (High byte) in Little endian
        *
        */
        const addrSpaceHolder LOWIP = 0x85;
        const addrSpaceHolder HIIP = 0x86;
        const addrSpaceHolder PCON = 0x87;
        const addrSpaceHolder TCON = 0x88;
        const addrSpaceHolder TMOD = 0x89;
        const addrSpaceHolder TL0 = 0x8A;
        const addrSpaceHolder TL1 = 0x8B;
        const addrSpaceHolder TH0 = 0x8C;
        const addrSpaceHolder TH1 = 0x8D;
        // 0x8E - 0x8F not used
        const addrSpaceHolder P1 = 0x90;
        // 0x91 - 0x97 not used
        const addrSpaceHolder SCON = 0x98;
        const addrSpaceHolder SBUF = 0x99;
        // 0x9a - 0x9f not used
        const addrSpaceHolder P2 = 0xA0;
        const addrSpaceHolder IE = 0xA8;
        // 0xa9 - 0xaf not used
        const addrSpaceHolder P3 = 0xB0;
        // 0xb1 - 0xb7 not used
        const addrSpaceHolder IP = 0xB8;
        // some extra registers here in ADUC, but not defined in base 8051?
        const addrSpaceHolder PSW = 0xD0;
        const addrSpaceHolder ACC = 0xE0;
        const addrSpaceHolder B = 0xF0;
        // some extra registers here in ADUC, but not defined in base 8051?

        const addrSpaceHolder BIT_Cary = 0xD7;
        const addrSpaceHolder BIT_Aux = 0xD6;
        const addrSpaceHolder BIT_General1 = 0xD5;
        const addrSpaceHolder BIT_Overflow = 0xD2;
        const addrSpaceHolder BIT_General2 = 0xD1;
        const addrSpaceHolder BIT_Parity = 0xD0;

        private Core_Window win = new Core_Window();

        public CommunicatorInterface DAS;
        public CommunicatorInterface PAS;



        private static byte ROR(byte b)
        {
          byte testLOB = (byte)((int)b & 0x01); // AND 0000-0001
          byte answer = (byte)((int)b >> 1);
          if (testLOB == 1)
            answer = (byte)((int)answer | 0x80); // OR 1000-0000
          return answer;
        }
        private static byte ROL(byte b)
        {
          byte testLOB = (byte)((int)b & 0x80); // AND 1000-0000
          byte answer = (byte)((int)b << 1);
          if (testLOB == 1)
            answer = (byte)((int)answer | 0x01); // OR 0000-0001
          return answer;
        }

        public void reset() { 
            // SET REGISTER DEFAULT VALUES
            DAS[ACC] = 0;
            DAS[B] = 0;
            DAS[PSW] = 0;
            DAS[SP] = 0x07;
            DAS[DPH] = 0;
            DAS[DPH] = 0;
            DAS[P0] = 0xff;
            DAS[P1] = 0xff;
            DAS[P2] = 0xff;
            DAS[P3] = 0xff;
            DAS[IP] = 0;
            DAS[IE] = 0;
            DAS[TMOD] = 0;
            DAS[TCON] = 0;
            DAS[TH0] = 0;
            DAS[TL0] = 0;
            DAS[TH1] = 0;
            DAS[TL1] = 0;
            DAS[SCON] = 0;
            DAS[SBUF] = 0;
            DAS[PCON] = 0;
        }

        public bool getBit(byte addr) {
            byte byteAddr;
            byteAddr = (byte)(addr & 0xf8); // get bits 1111 1111 1000
            byte bitAddr = (byte)(addr & 0x07); // bitAddr is byte with one bit set to 1
            bitAddr = (byte)Math.Pow((double)2, (double)bitAddr);
            return ((DAS[byteAddr] & bitAddr) == 0) ? false : true ;
        }
        public void setBit(bool bit, byte addr) {
            byte byteAddr = (byte)(addr & 0xf8); // get bits 1111 1111 1000
            byte bitAddr = (byte)(addr & 0x07);
            bitAddr = (byte)Math.Pow((double)2, (double)bitAddr); // bitAddr is byte with one bit set to 1
            byte tempByte = DAS[byteAddr];
            if (bit) tempByte |= bitAddr; // set bit
            else tempByte &= (byte)~bitAddr; // clear bit
            DAS[byteAddr] = tempByte;
        }

        public Core_controlxaml()
        {
            InitializeComponent();
  
            // Register mouse click event
            this.MouseDown += new MouseButtonEventHandler(this.my_MouseDown); 

            //Uri ur = new Uri("c:/64.jpg", UriKind.RelativeOrAbsolute);
            //this.Source = new System.Windows.Media.Imaging.BitmapImage(ur);
            


        }

        // helper function for operating with 2byte IP register in 1byte RAM
        public int getIP() {
            int x = DAS[HIIP];
            x <<= 8;
            x += DAS[LOWIP];
            return x;
        }

        public void setIP(int x) {
            byte temp = (byte)x;
            DAS[LOWIP] = temp;
            temp = (byte)(x >> 8);
            DAS[HIIP] = temp;
        }

        public void incIP() {
            setIP(getIP() + 1);
        }


        // device must implement CommunicatorInterface
        public void registerDAS(CommunicatorInterface device)
        {
            DAS = device;
        }

        // device must implement CommunicatorInterface
        public void registerPAS(CommunicatorInterface device)
        {
            PAS = device;
        }
        
        public byte getCurrentRegisterBankOffset() {
            byte temp = DAS[PSW];
            // getting 0001 1000 bits
            temp >>= 2;
            temp &= 0x03;
            return (byte)(temp * 0x08); // each register bank is 8byte array
        }

        private void my_MouseDown(object sender, MouseEventArgs e)
        {
            win.Show();
        }

        public void tick()
        {

            return; //not implemented yet
           // char x = DAS[0];
            //MessageBox.Show("hello!");

            
            int curentIP = getIP();
            byte curentInstrCode = PAS[curentIP];
                // NOP. 1c 1b
            if (curentInstrCode == 0x00)
            {
                incIP();
            }
            // AJMP addr11. 2c 2b
            else if ((curentInstrCode & 0x1f) == 0x01)
            {
                int jumpAddr = curentInstrCode & 0xE0; // clearing bits. 1110 0000
                jumpAddr = jumpAddr << 3;
                jumpAddr += PAS[curentIP + 1]; // seting bits 0-7
                int newIP = getIP();
                newIP += 2;
                newIP = newIP & 0xFC00; // clearing bits 1111 1100 0000 0000
                newIP = newIP | jumpAddr; // seting low 10 bits of IP to new value
                setIP(newIP);
                //
            }
            // LJMP addr16. 2c 3b
            else if (curentInstrCode == 0x02)
            {
                DAS[HIIP] = PAS[curentIP + 1];
                DAS[LOWIP] = PAS[curentIP + 2];
            }
            // RR A. 1c
            else if (curentInstrCode == 0x03)
            {
                byte temp = DAS[ACC];
                temp = ROR(temp);
                DAS[ACC] = temp;
                incIP();
            }
            // INC A. 1c 1b
            else if (curentInstrCode == 0x04)
            {
                DAS[ACC]++;
                incIP();
            }
            // INC data addr. 1c 2b
            else if (curentInstrCode == 0x05)
            {
                byte temp = PAS[curentIP + 1];
                DAS[temp]++;
                incIP();
            }
            // INC @Rx. 1c 1b
            else if ((curentInstrCode & 0xfe) == 0x06)
            {
                curentInstrCode &= 0xfe;
                byte addr = DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                DAS[addr]++;
                incIP();
            }
            // INC Rx. 1c 1b
            else if ((curentInstrCode & 0xf8) == 0x08)
            {
                curentInstrCode &= 0x07;
                DAS[getCurrentRegisterBankOffset() + curentInstrCode]++;
                incIP();
            }
            // JBC bit addr, code addr  2c 3b
            else if (curentInstrCode == 0x10)
            {
                setIP(getIP() + 3);
                if (getBit(PAS[curentIP + 1]))
                {
                    setBit(false, PAS[curentIP]);
                    setIP(getIP() + PAS[curentIP + 2]);
                }
            }
            // ACALL  2c 2b
            else if ((curentInstrCode & 0x11) == 0x11)
            {
                setIP(getIP() + 2);
                DAS[SP]++;
                DAS[DAS[SP]] = DAS[LOWIP];
                DAS[SP]++;
                DAS[DAS[SP]] = DAS[HIIP];

                int tempIP = curentInstrCode >> 5;
                tempIP <<= 8;
                tempIP += PAS[curentIP + 1];
                int prevIP = getIP();
                prevIP &= 0xf800; // save only 5 bits
                prevIP += tempIP;
                setIP(prevIP);
            }
            // LCALL 2c 3b
            else if (curentInstrCode == 0x12)
            {
                setIP(getIP() + 3);
                DAS[SP]++;
                DAS[DAS[SP]] = DAS[LOWIP];
                DAS[SP]++;
                DAS[DAS[SP]] = DAS[HIIP];
                DAS[HIIP] = PAS[curentIP + 1];
                DAS[LOWIP] = PAS[curentIP + 2];
            }
            // RRC 1c 1b
            else if (curentInstrCode == 0x13)
            {
                // @TODO
                incIP();
            }
            // DEC A  1c 1b
            else if (curentInstrCode == 0x14)
            {
                DAS[ACC]--;
                incIP();
            }
            // DEC addr 1c 2b
            else if (curentInstrCode == 0x15)
            {
                DAS[PAS[curentIP + 1]]--;
                incIP();
            }
            // DEC @Rn 1c 1b
            else if ((curentInstrCode & 0x16) == 0x16)
            {
                curentInstrCode &= 0xfe;
                byte addr = DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                DAS[addr]--;
                incIP();
            }
            // DEC Rn 1c 1b
            else if ((curentInstrCode & 0x18) == 0x18)
            {
                curentInstrCode &= 0x07;
                DAS[getCurrentRegisterBankOffset() + curentInstrCode]--;
                incIP();
            }
            // JB bit,addr 2c 3b
            else if (curentInstrCode == 0x20)
            {
                setIP(getIP() + 3);
                if (getBit(PAS[curentIP + 1]))
                {
                    setIP(getIP() + PAS[curentIP + 2]);
                }
            }
            // RET 1b 2c 
            else if (curentInstrCode == 0x22)
            {
                DAS[HIIP] = DAS[DAS[SP]];
                DAS[SP]--;
                DAS[LOWIP] = DAS[DAS[SP]];
                DAS[SP]--;
            }
            // RL A 1b 1c
            else if (curentInstrCode == 0x23)
            {
                DAS[ACC] = ROL(DAS[ACC]);
                incIP();
            }
            // ADD A,#data 2b 1c
            else if (curentInstrCode == 0x24)
            {
                DAS[ACC] += PAS[curentIP + 1];
                incIP();
            }
            // ADD data addr 2b 1c
            else if (curentInstrCode == 0x25)
            {
                DAS[ACC] += DAS[PAS[curentIP + 1]];
                incIP();
            }
            // ADD A, @Ri
            else if ((curentInstrCode & 0x26) == 0x26)
            {
                curentInstrCode &= 0xfe;
                byte addr = DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                DAS[ACC] += DAS[addr];
                incIP();
            }
            // ADD A, Rn 1b 1c
            else if ((curentInstrCode & 0x28) == 0x28)
            {
                curentInstrCode &= 0x07;
                DAS[ACC] += DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                incIP();
            }
            // JNB bit, rel 3b 2c
            else if (curentInstrCode == 0x30)
            {
                setIP(getIP() + 3);
                if (!getBit(PAS[curentIP + 1]))
                    setIP(getIP() + PAS[curentIP + 2]);
            }
            // RETI  1b 2c
            else if (curentInstrCode == 0x32)
            {
                DAS[HIIP] = DAS[DAS[SP]];
                DAS[SP]--;
                DAS[LOWIP] = DAS[DAS[SP]];
                DAS[SP]--;
            }
            // RLC A 1b 1c
            else if (curentInstrCode == 0x33)
            {
                // @TODO
                incIP();
            }
            // ADDC A,#data 2b 1c 
            else if (curentInstrCode == 0x34)
            {
                DAS[ACC] += (byte)((getBit(BIT_Cary) ? 1 : 0) + PAS[curentIP + 1]);
                incIP();
            }
            // ADDC A,data addr 2b 1c 
            else if (curentInstrCode == 0x35)
            {
                DAS[ACC] += (byte)(getBit(BIT_Cary) ? 1 : 0 + DAS[PAS[curentIP + 1]]);
                incIP();
            }
            // ADDC A,@Ri 1b 1c
            else if ((curentInstrCode & 0x36) == 0x36)
            {
                curentInstrCode &= 0xfe;
                byte addr = DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                DAS[ACC] += (byte)(getBit(BIT_Cary) ? 1 : 0 + DAS[addr]);
                incIP();
            }
            // ADDC A,Rn 1b 1c
            else if ((curentInstrCode & 0x38) == 0x38)
            {
                curentInstrCode &= 0x07;
                DAS[ACC] += (byte)(getBit(BIT_Cary) ? 1 : 0 + DAS[getCurrentRegisterBankOffset() + curentInstrCode]);
                incIP();
            }
            // JC code addr 2b 2c
            else if (curentInstrCode == 0x40)
            {
                setIP(getIP() + 2);
                if (getBit(BIT_Cary))
                {
                    setIP(getIP() + PAS[curentIP + 1]);
                }
            }
            // ORL  data addr,A 2b 1c
            else if (curentInstrCode == 0x42)
            {
                DAS[PAS[curentIP + 1]] |= DAS[ACC];
                incIP();
            }
            // ORL direct data  3b 2c
            else if (curentInstrCode == 0x43)
            {
                DAS[PAS[curentIP + 1]] |= PAS[curentIP + 2];
                incIP();
            }
                // ORL A,#data 2b 1c
            else if (curentInstrCode == 0x44) {
                DAS[ACC] |= PAS[curentIP + 1];
                incIP();
            }
                // ORL A,direct 2b 1c
            else if (curentInstrCode == 0x45)
            {
                DAS[ACC] |= DAS[PAS[curentIP + 1]];
                incIP();
            }
                // ORL A,@Ri 1b 1c
            else if ((curentInstrCode & 0x46) == 0x46)
            {
                curentInstrCode &= 0xfe;
                byte addr = DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                DAS[ACC] |= (byte)DAS[addr];
                incIP();
            }
                // ORL A,Rn  1b 1c
            else if ((curentInstrCode & 0x48) == 0x48)
            {
                curentInstrCode &= 0x07;
                DAS[ACC] |= (byte)DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                incIP();
            }
                // JNC code addr 2b 2c 
            else if (curentInstrCode == 0x50)
            {
                setIP(getIP() + 2);
                if (!getBit(BIT_Cary)) { 
                    setIP(getIP() + PAS[curentIP + 1]);
                }
            }
                // ANL direct,A  2b 1c
            else if(curentInstrCode == 0x52){
                DAS[PAS[curentIP + 1]] &= DAS[ACC];
                incIP();
            }
                // ANL direct,#data 3b 2c 
            else if(curentInstrCode == 0x53){
                DAS[PAS[curentIP + 1]] &= PAS[curentIP + 2];
                incIP();
            }
                // ANL A,#data  2b 1c
            else if(curentInstrCode == 0x54){
                DAS[ACC] &= PAS[curentIP + 1];
                incIP();
            }
                // ANL A,addr 2b 1c
            else if(curentInstrCode == 0x55){
                DAS[ACC] &= DAS[PAS[curentIP + 1]];
                incIP();
            }
                // ANL A,@Ri 1b 1c
            else if((curentInstrCode & 0x56)== 0x56){
                curentInstrCode &= 0xfe;
                byte addr = DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                DAS[ACC] &= (byte)DAS[addr];
                incIP();
            }
                // ANL A,Rn 1b 1c
            else if((curentInstrCode & 0x58)== 0x58){
                curentInstrCode &= 0x07;
                DAS[ACC] &= (byte)DAS[getCurrentRegisterBankOffset() + curentInstrCode];
                incIP();
            }
                // JZ rel  2b 2c
            else if(curentInstrCode == 0x60){
                setIP(getIP() + 2);
                if(DAS[ACC] == 0){
                    setIP(getIP() + PAS[curentIP + 1]);
                }
            }
            



           }
        }


}




